﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Transactions;
using T.FAS.Runtime.Metadata.Client;
using T.FAS.Runtime.Metadata.Entity;
using T.FAS.Runtime.Metadata.Service;

//using T.FAS.Runtime.Metadata.Client;
using T.FAS.Runtime.Metadata.SPI;

namespace T.FAS.Runtime.DataModel.Plugin
{
    /// <summary>
    /// 拆分出来的运行时RTP Manager
    /// 目前FASRM FASR都使用运行时环境的FAS库，读取同一套MetaTypeInfo配置
    /// </summary>
    public abstract class AbsRTPMetaDataManager : AbsMetaDataManager, IMetaDataManager
    {
        private readonly MetaDataClientService _metaDataClientService = MetaDataClientService.GetInstance();
       
        #region Abs Method Definition
        /************************FASR使用的接口方法***************************/
        public abstract IMetaDataContent GetMetaDataContent(string metaDataId);
        public abstract IMetaDataContent DeserializeObject(string metaDataString, MetadataSerializeType serializeType);
        public abstract IMetaDataContent DeserializeObject(string metaDataString, bool isPackingData = false);
        public abstract string SerializeObject(IMetaDataContent metadata, MetadataSerializeType serializeType);

        /************************FASRM使用的接口方法***************************/
        public abstract void Import(List<IMetaDataContent> contents);

        //public abstract void Delete(List<IMetaDataContent> contents);
        public abstract void Delete(List<string> IDs);
        //public abstract ConflictMessage ConflictCheck(List<IMetaDataContent> releasedMetaData, IMetaDataContent releaseingMetaData);
        //public abstract void Delete(IMetaDataContent metaData);
        //public abstract void Update(IMetaDataContent metaData);
        //public abstract void Save(IMetaDataContent metaData);
        //public abstract ValidateResult Validate(IMetaDataContent metaData);
        //public abstract MetaDataCompileResult Compile(IList<IMetaDataContent> metadatas);
        //public abstract List<MetaDataDependency> GetMetaDataDependencys(IMetaDataContent metaDataContent);
        //public abstract MetaDataUpdateSet GetMetaDataUpdateSet(IMetaDataContent oldMetaData, IMetaDataContent newMetaData);
        //public abstract MetaUpdateResult UpdateDependencyMetaData(IMetaDataContent metaDataContent, MetaDataUpdateSet updateSet);

        #endregion

        public virtual IList<MetaDataExportContent> Export(params IMetaDataContent[] metaDataList)
        {
            var contents = new List<MetaDataExportContent>();

            foreach (var item in metaDataList)
            {
                var exportContent = new MetaDataExportContent
                {
                    Content = this.SerializeObject(item, MetadataSerializeType.JSON),
                    ExportType = MetaDataExportType.JSON,
                    MetaDataId = item.MetaDataID,
                    MetaDataCode = item.MetaDataCode,
                    MetaDataType = item.MetaData.MetaTypeID,
                    TenantID = item.MetaData.TenantId,
                };
                //dynamic metaDataObject = item;
                //exportContent.TenantID = metaDataObject.TenantID;
                contents.Add(exportContent);
            }

            return contents;
        }

        public void Import(IList<MetaDataExportContent> contents, MetaDataImportStrategy importStrategy)
        {
            if (contents == null || contents.Count < 1)
                return;

            if (importStrategy == MetaDataImportStrategy.Replace)
            {
                var list = new List<IMetaDataContent>();
                foreach (var exportContent in contents)
                {
                    dynamic content = this.DeserializeObject(exportContent.Content);
                    content.MetaDataID = exportContent.MetaDataId;
                    content.MetaDataCode = exportContent.MetaDataCode;
                    content.TenantID = exportContent.TenantID;
                    list.Add(content);
                }
                //如果Manager为DO，则执行导入前方法，比较DO差异，生成Alter Column语句
                if (this is DataObjectRTPManager doManager)
                {
                    doManager.PreImportFunc(list);
                }

                TransactionOptions transactionoptions = new TransactionOptions(){IsolationLevel = IsolationLevel.ReadCommitted
                };
                using (var scope = new TransactionScope(TransactionScopeOption.Required, transactionoptions))
                {
                    this.Import(list);

                    scope.Complete();
                }
            }
            else if (importStrategy == MetaDataImportStrategy.Delete)
            {
                var Ids = contents.Select(con => con.MetaDataId).ToList();
                this.Delete(Ids);
            }
        }

        #region FASRM FASR中不需要实现的方法
        public virtual void Enable(params IMetaDataContent[] metaData)
        {

        }

        public virtual void Release(IMetaDataContent metaData, ReleaseStrategy releaseStrategy)
        {

        }

        public virtual void Delete(IMetaDataContent metaData)
        {
            throw new NotImplementedException();
        }

        public virtual void Update(IMetaDataContent metaData)
        {
            throw new NotImplementedException();
        }

        public virtual void Save(IMetaDataContent metaData)
        {
            throw new NotImplementedException();
        }

        public virtual ValidateResult Validate(IMetaDataContent metaData)
        {
            throw new NotImplementedException();
        }

        public virtual ConflictMessage ConflictCheck(List<IMetaDataContent> releasedMetaData, IMetaDataContent releaseingMetaData)
        {
            throw new NotImplementedException();
        }

        public virtual MetaDataCompileResult Compile(IList<IMetaDataContent> metadatas)
        {
            throw new NotImplementedException();
        }

        public virtual List<MetaDataDependency> GetMetaDataDependencys(IMetaDataContent metaDataContent)
        {
            throw new NotImplementedException();
        }

        public virtual MetaDataUpdateSet GetMetaDataUpdateSet(IMetaDataContent oldMetaData, IMetaDataContent newMetaData)
        {
            throw new NotImplementedException();
        }

        public virtual MetaUpdateResult UpdateDependencyMetaData(IMetaDataContent metaDataContent, MetaDataUpdateSet updateSet)
        {
            throw new NotImplementedException();
        }
        #endregion

        #region Private Funcs
        /// <summary>
        /// 运行时获取元数据内容
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="metaId"></param>
        /// <param name="isThrowException">是否抛出异常，true是 false否</param>
        /// <returns></returns>
        protected T GetMetaData<T>(string metaId, bool isThrowException = true)
        {
            var data = _metaDataClientService.GetMetaDataContent(metaId);
            var typeName = typeof(T).Name;
            if (data == null && isThrowException)
                throw new Exception($"运行时获取元数据:{typeName}失败，metaId:{metaId}");
            if (data is T tdata)
            {
                return tdata;
            }
            if (isThrowException)
                throw new Exception($"运行时获取元数据:{typeName}失败:{metaId}");
            else
                return default;
        }

        /// <summary>
        /// 设计时获取元数据内容
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="metaId"></param>
        /// <param name="branchId"></param>
        /// <param name="isThrowException">是否抛出异常，true是 false否</param>
        /// <returns></returns>
        protected T GetMetaDataWithNoDeserialize<T>(string metaId, bool isThrowException = true) where T : IMetaDataContent
        {
            var contentJson = _metaDataClientService.GetMetaDataWithNoDeSerialize(metaId);
            var typeName = typeof(T).Name;
            if (string.IsNullOrEmpty(contentJson) && isThrowException)
                throw new Exception($"运行时获取元数据:{typeName}Json失败，metaId:{metaId}");
            T tdata = default;
            try
            {
                tdata = JsonConvert.DeserializeObject<T>(contentJson, new JsonSerializerSettings
                {
                    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                });
            }
            catch
            {
                if (isThrowException)
                    throw new Exception($"运行时获取元数据:{typeName}失败:{metaId}");
            }
            if (tdata == null && isThrowException)
                throw new Exception($"运行时获取元数据:{typeName}失败:{metaId}");
            else
            {
                dynamic tmp = tdata;
                tmp.ID = tdata.MetaDataID;
                tmp.Code = tdata.MetaDataCode;
                tmp.Name = tdata.MetaDataName;
                return tdata;
            }
        }

        public abstract IRefSchemaEntity BuildRefSchema(IMetaDataContent metaDataContent);
        public abstract IEnumerable<Metadata.Entity.Term> BuildTerms(IMetaDataContent metaDataContent, IEnumerable<Metadata.Entity.Term> termList = null);
        public abstract IRefSchemaEntity DeserializeRefSchemaEntity(string schemaEntityJson);
        #endregion

        public enum CRUDType
        {
            CREATE,
            RETRIEVE,
            UPDATE,
            DELETE,
        }
        ValidateResult IMetaDataManager.CompatibleValidate(IMetaDataContent metaData, IMetaDataContent oldMetaData)
        {
            return new ValidateResult {  state = "1" };
        }

        public override MetaGenerateCodeResult GenerateCode(IMetaDataContent metadata, bool isInternational)
        {
            return new MetaGenerateCodeResult();
        }
    }
}
